package mymyoux.io.sql
{
	import flash.data.SQLColumnNameStyle;
	import flash.data.SQLConnection;
	import flash.data.SQLMode;
	import flash.errors.SQLError;
	import flash.events.SQLErrorEvent;
	import flash.events.SQLEvent;
	import flash.filesystem.File;
	import flash.utils.ByteArray;
	
	import mymyoux.signals.Signal;

	/**
	 * Create a SQL connection
	 */
	public class SQL
	{
		/**
		 * Native SQL Connection object
		 */
		private var _sqlConnection:SQLConnection;
		/**
		 * @private
		 */
		private var _signalOpen:Signal;
		/**
		 * @private
		 */
		private var _signalError:Signal;
		
		/**
		 * @private
		 */
		private var _autoCompact:Boolean;
		/**
		 * @private
		 */
		private var _encryptionKey:String;
		/**
		 * @private
		 */
		private var _openMode:String;
		/**
		 * @private
		 */
		private var _pageSize:uint;
		
		/**
		 * Create a SQL object
		 */
		public function SQL()
		{
			_signalOpen = new Signal();
			_signalError = new Signal(SQLError);
			
			openMode = SQLMode.CREATE;
			autoCompact = false;
			pageSize = 1024;
			encryptionKey = null;
			
			_sqlConnection = new SQLConnection();
			_sqlConnection.addEventListener(SQLEvent.OPEN, onDatabaseOpen);
			_sqlConnection.addEventListener(SQLErrorEvent.ERROR, onDatabaseError);
		}
		
		/**
		 * Cache size
		 */
		public function get cacheSize():uint
		{
			return _sqlConnection.cacheSize;
		}
		
		public function set cacheSize(value:uint):void
		{
			_sqlConnection.cacheSize = value; 
		}
		
		/**
		 * Column style
		 */
		public function get columnNameStyle():String
		{
			return _sqlConnection.columnNameStyle;
		}
		
		public function set columnNameStyle(value:String):void
		{
			switch(value)
			{
				case SQLColumnNameStyle.DEFAULT:
				case SQLColumnNameStyle.LONG:
				case SQLColumnNameStyle.SHORT:
					break;					
				default:
					throw(new Error(value+" is not a correct value. see SQLColumnNameStyle constants"));
			}
			_sqlConnection.columnNameStyle = value;
		}
		
		/**
		 * Indicates if the connection is etablished
		 */
		public function get connected():Boolean
		{
			return _sqlConnection.connected;
		}
		/**
		 * Encryption key, can reencrypt a preencrypted database
		 */
		public function get encryptionKey():String
		{
			return _encryptionKey;
		}

		public function set encryptionKey(value:String):void
		{
			_encryptionKey = value;
			if(_sqlConnection != null && connected)
			{
				var byteArray:ByteArray = new ByteArray();
				byteArray.writeUTF(encryptionKey);
				_sqlConnection.reencrypt(byteArray);
			}
		}
		/**
		 * Page size.
		 * The value must be a power of two greater than or equal to 512 and less than or equal to 32768
		 */
		public function get pageSize():uint
		{
			return _pageSize;
		}

		public function set pageSize(value:uint):void
		{
			if(value < 512 || value > 32768 || value % 512 != 0)
			{
				throw(new Error("The value must be a power of two greater than or equal to 512 and less than or equal to 32768. Actual value = "+value));	
			}
			_pageSize = value;
		}

		/**
		 * Auto compact. CPU consumption cost
		 */
		public function get autoCompact():Boolean
		{
			return _autoCompact;
		}

		public function set autoCompact(value:Boolean):void
		{
			_autoCompact = value;
		}

		/**
		 * Open Mode 
		 */
		public function get openMode():String
		{
			return _openMode;
		}

		public function set openMode(value:String):void
		{
			switch(value)
			{
				case SQLMode.CREATE:
				case SQLMode.READ:
				case SQLMode.UPDATE:
				break;					
				default:
					throw(new Error(value+" is not a correct value. see SQLMode constants"));
			}
			_openMode = value;
		}
		/**
		 * Signal() dispatches when the connection is opened.
		 */
		public function get signalOpen():Signal
		{
			return _signalOpen;
		}
		/**
		 * Signal(SQLError) dispatches when a error occurs
		 */
		public function get signalError():Signal
		{
			return _signalError;
		}
		/**
		 * Native SQL Connection
		 */
		public function get sqlConnection():SQLConnection
		{
			return _sqlConnection;
		}
		/**
		 * Open a synchronous connection
		 * @param file Url file of the database
		 */
		public function open(file:String):void
		{
			var byteArray:ByteArray;
			if(encryptionKey != null)
			{
				byteArray = new ByteArray();
				byteArray.writeUTF(encryptionKey);	
			}
			var dbFile:File = File.applicationStorageDirectory.resolvePath(file);
		//	dbFile.save(
			_sqlConnection.open(dbFile, openMode, autoCompact, pageSize, byteArray);
		}
		/**
		 * Open an asynchronous connection
		 * @param file Url file of the database
		 */
		public function openAsynchronously(file:String):void
		{
			var byteArray:ByteArray;
			if(encryptionKey != null)
			{
				byteArray = new ByteArray();
				byteArray.writeUTF(encryptionKey);	
			}
			var dbFile:File = File.applicationStorageDirectory.resolvePath(file);
			_sqlConnection.openAsync(dbFile, openMode, null, autoCompact, pageSize, byteArray);
		}
		/**
		 * @private
		 */
		protected function onDatabaseOpen(event:SQLEvent):void
		{
			_signalOpen.dispatch();		
		}
		/**
		 * @private
		 */
		protected function onDatabaseError(event:SQLErrorEvent):void
		{
			_signalError.dispatch(event.error);
		}
	}
}